home *** CD-ROM | disk | FTP | other *** search
- /* LAP802Arp.c contains Address Resolution Protocol handler for IEEE 802.3 LAP
-
- (c) Copyright 1990-91 by Apple Computer, Inc. All rights reserved.
-
- */
-
- /*
- 1.2 Oct 1990 Rajesh - modified to add IEEE 802.3 LAP flavor.
- 1.0d4 7/13/88 JEM Fixed IOComplete on ARP time-out
- 6/10/88 JEM Put LAP's into separate code segments
- 1.0d2 1/13/88 JEM Convert to MPW
- 1.0d1 9/14/87 JEM Initial version for MacOS
- */
-
- #include <OSUtils.h>
- #include <Retrace.H>
- #include <Devices.h>
- #include <Memory.h>
- #include <Traps.h>
- #include <AppleTalk.h>
-
- #include "MacTCPCommonTypes.h"
- #include "MiscIPPB.h"
- #include "LAPMisc.h"
- #include "LAP802.h"
-
- #define MAX_AGE 10*60*6 /* time-out ARP cache entry if unused for 10 minutes */
- #define MAX_RTX 4 /* RTX ARP request 4 times */
-
- #define ARP_VRT_COUNT 10 /* RTX ARP every 160 msec. */
- #define ARP_VRT_PHASE 5
-
-
- /* internal procedure prototype definitions */
- pascal void Arp_vrt_handler(void);
-
- struct arp_entry *new_arp_entry(struct Lap802Info *lap, b_16 prot, Lap802_addr sha, ip_addr spa);
- struct arp_entry *get_arp_entry(struct Lap802Info *lap, ip_addr addr);
-
- extern void Enable(short oldPS);
- extern short Disable(void);
- extern Boolean broadcastAddr(struct LAPInfo *lap, ip_addr addr);
-
-
- OSErr Arp_init(lap)
- struct Lap802Info *lap;
- {
- struct ipbuf *ipb;
- struct Lap802_header *lap_hdr;
- struct arp_header *arp_hdr;
-
- bzero((char *)&lap->arp_q, sizeof(lap->arp_q));
- bzero((char *)&lap->arp_table[0], sizeof(lap->arp_table));
-
- /* set-up ARP sending IPB */
- ipb = (struct ipbuf *) NewPtr(sizeof(struct ipbuf) +
- sizeof(struct Lap802_header) + sizeof(struct arp_header));
- lap->arp_ipb = ipb;
- bzero((char *)ipb, sizeof(struct ipbuf));
-
- lap_hdr = (struct Lap802_header *)(ipb+1);
- ipb->laphdr.ptr = (char *)lap_hdr;
- ipb->laphdr.length = sizeof(struct Lap802_header);
- /* lap_len can be zero, since we always calculate length before writing */
- lap_hdr->lap_len = sizeof(struct arp_header) + 8; /* sizeof(struct LLC_SNAP_header) = 3,LLC + 5,SNAP = 8 RAJESH */
- lap_hdr->lap_ls.lap_dsap = HEX_AA;
- lap_hdr->lap_ls.lap_ssap = HEX_AA;
- lap_hdr->lap_ls.lap_cntl = HEX_3;
- lap_hdr->lap_ls.lap_orghi = 0;
- lap_hdr->lap_ls.lap_orglo = 0;
- lap_hdr->lap_ls.lap_type = LAP_ARP;
-
- arp_hdr = (struct arp_header *)(lap_hdr+1);
- ipb->ip.ptr = (struct ip4_header *)arp_hdr; /* reuse this entry for ARP's header */
- ipb->ip.length = sizeof(struct arp_header);
- ipb->tp.length = 0;
-
- arp_hdr->arp_hardware = ARP_ETHERNET;
- arp_hdr->arp_protocol = LAP_IP;
- arp_hdr->arp_hlen = sizeof(struct Lap802_addr);
- arp_hdr->arp_plen = sizeof(ip_addr);
- arp_hdr->arp_sha = lap->our_lap_addr;
- ipb->iop.ioCompletion = nil;
-
- /* insert task into the vertical retrace queue to time-out ARP requests
- and age ARP cache entries */
- lap->arp_vrt_info.VBL.qType = vType;
- lap->arp_vrt_info.VBL.vblAddr = Arp_vrt_handler;
- lap->arp_vrt_info.VBL.vblCount = ARP_VRT_COUNT;
- lap->arp_vrt_info.VBL.vblPhase = ARP_VRT_PHASE;
- lap->arp_vrt_info.vblA5 = (Ptr)lap;
-
- return(VInstall((QElemPtr)&lap->arp_vrt_info.VBL));
- }
-
- /* Arp_vrt_handler is called by the vertical retrace manager to age ARP cache entries and
- retransmit ARP requests. A0 = VBLTask entry */
-
- pascal void Arp_vrt_handler()
- {
- struct Lap802Info *lap;
- struct ipbuf *ipb;
- struct ipbuf *next_ipb;
- struct arp_entry *ap;
- struct arp_info *arp;
- short oldPS;
-
- lap = (struct Lap802Info *) ((struct VBLTaskA5 *) GetA0())->vblA5;
- lap->arp_vrt_info.VBL.vblCount = ARP_VRT_COUNT;
-
- /* crawl through ARP queue timing out packets */
- oldPS = Disable();
- ipb = (struct ipbuf *)lap->arp_q.qHead;
- while (ipb) {
- next_ipb = (struct ipbuf *)ipb->iop.qLink;
- arp = (struct arp_info *)ipb->laphdr.ptr;
- arp->timer--;
- if (arp->timer < 0) {
- /* packet has timed out */
- arp->rtx++;
- if (arp->rtx < MAX_RTX) {
- /* we'll try again and send an ARP */
- arp->timer = 3;
- SendARP(lap, ARP_REQUEST, arp->addr, &lap->lap_broadcast_addr);
- }
- else {
- /* no-one responded to the ARP, discard packet in error */
- Dequeue((QElemPtr)ipb, &lap->arp_q);
- ipb->iop.ioResult = ipDestDeadErr;
- IOComplete(ipb);
- }
- }
- ipb = next_ipb;
- }
-
- /* now time-out ARP table entries */
- for (ap = &lap->arp_table[0]; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
- if (ap->ip_address != nil) {
- ap->age++;
- if (ap->age > MAX_AGE) {
- ap->ip_address = nil;
- }
- }
- }
- Enable(oldPS);
- }
-
-
- /* Arp_read_ph is called directly by the IEEE 802.3 packet read handler when an
- ARP type packet is received. */
-
- void Arp_read_ph(rds)
- struct rdStruct *rds;
- {
- struct Lap802Info *lap;
- struct arp_entry *ap;
- struct Lap802_header *lap_hdr;
- struct ipbuf *ipb;
- struct ipbuf *next_ipb;
- short oldPS;
-
- lap = (struct Lap802Info *) rds->lap;
-
- /* call ReadRest to finish reading in packet, but only enough
- for IP-type ARPs */
- if (ReadRest(rds, (char *)&lap->arp_rcv, sizeof(lap->arp_rcv)) <= 0) {
- /* if enough received, check ARP header */
- if ((lap->arp_rcv.arp_hardware == ARP_ETHERNET) &&
- (lap->arp_rcv.arp_protocol == LAP_IP)) {
- /* Is the pair <protocol type, sender protocol address>
- already in the arp table? */
- oldPS = Disable();
- ap = get_arp_entry(lap,lap->arp_rcv.arp_spa);
-
- if (ap) {
- /* If yes, update with the new hardware address */
- ap->lap_address = lap->arp_rcv.arp_sha;
- }
-
- if ((lap->arp_rcv.arp_spa == lap->our_ip_addr) &&
- (lap->arp_rcv.arp_opcode == ARP_REPLY)) {
- /* we have received a reply when we ARPed on our address */
- lap->addressConflict = true;
- }
- else if (lap->arp_rcv.arp_tpa == lap->our_ip_addr) {
- /* since packet sent to us, process it */
- if (ap == nil) {
- /* Save sender entry in table since this host will
- probably want to talk to us soon */
- ap = new_arp_entry(lap, lap->arp_rcv.arp_protocol,
- lap->arp_rcv.arp_sha, lap->arp_rcv.arp_spa);
- }
-
- /* Look at opcode */
- if (lap->arp_rcv.arp_opcode == ARP_REQUEST) {
- /* response with our IEEE 802.3 address */
- SendARP (lap, ARP_REPLY, lap->arp_rcv.arp_spa,
- &((struct Lap802_header *)rds->laphdr.ptr)->lap_src);
- }
- else if (lap->arp_rcv.arp_opcode == ARP_REPLY) {
- /* dequeue packet waiting ARP and send it */
- ipb = (struct ipbuf *)lap->arp_q.qHead;
- while (ipb) {
- next_ipb = (struct ipbuf *)ipb->iop.qLink;
- if (((struct arp_info *)(ipb->laphdr.ptr))->addr == ap->ip_address) {
- /* dequeue packet from ARP queue and send it */
- ap->age = 0;
- lap_hdr = (struct Lap802_header *)ipb->laphdr.ptr;
- lap_hdr->lap_dest = ap->lap_address;
- lap_hdr->lap_ls.lap_type = LAP_IP;
- Dequeue((QElemPtr)ipb, &lap->arp_q);
- /* start IEEE 802.3 output */
- Lap802_writeit(lap, ipb);
- }
- /* look at next packet in queue */
- ipb = next_ipb;
- }
- }
- }
- Enable(oldPS);
- }
- }
- }
-
- /* RARP_read_ph is called directly by the IEEE 802.3 packet read handler when an
- RARP type packet is received. */
-
- void RARP_read_ph(rds)
- struct rdStruct *rds;
- {
- struct Lap802Info *lap;
-
- lap = (struct Lap802Info *) rds->lap;
-
- /* call ReadRest to finish reading in packet, but only enough
- for IP-type RARPs */
- if (ReadRest(rds, (char *)&lap->arp_rcv, sizeof(lap->arp_rcv)) <= 0) {
- /* if enough received, check RARP header */
- if ((rds->lapBroadcast == false) &&
- (lap->arp_rcv.arp_hardware == ARP_ETHERNET) &&
- (lap->arp_rcv.arp_tha.lap_lo == lap->our_lap_addr.lap_lo)) {
- /* since packet sent to us (most likely), process it */
- /* Look at opcode */
- if (lap->arp_rcv.arp_opcode == RARP_REPLY) {
- if (lap->our_ip_addr == 0) {
- /* our address is unknown, take it from RARP reply */
- lap->our_ip_addr = lap->arp_rcv.arp_tpa;
- lap->lc.configIPAddr = LAPcnfg;
- }
- }
- }
- }
- }
-
- /* IP_to_Lap802 is called to translate an IP address into an IEEE 802.3
- address by using ARP */
-
- struct Lap802_addr *IP_to_Lap802(lap, addr)
- struct Lap802Info *lap;
- ip_addr addr;
- {
- struct arp_entry *ap;
- struct Lap802_addr *enp;
- short oldPS;
-
- if (broadcastAddr((struct LAPInfo *)lap, addr))
- /* convert IP broadcast address into IEEE 802.3 broadcast */
- return(&lap->lap_broadcast_addr);
-
- /* check if our IP address, if so, return our Lap802 address since we won't
- respond to the ARP */
- if (addr == lap->our_ip_addr)
- return(&lap->our_lap_addr);
-
- /* search through ARP table */
- oldPS = Disable();
- ap = get_arp_entry(lap, addr);
- if (ap) {
- /* reset age field to reflect access */
- ap->age = 0;
- enp = &ap->lap_address;
- }
- else
- enp = nil;
- Enable(oldPS);
- return(enp);
- }
-
-
- void Arp_close(lap)
- struct Lap802Info *lap;
- {
- VRemove((QElemPtr)&lap->arp_vrt_info.VBL);
- DisposPtr((Ptr)lap->arp_ipb);
- lap->arp_ipb = nil;
- }
-
-
- void SendARP (lap,arp_code,ip_dest,lap_dest)
- struct Lap802Info *lap;
- int arp_code;
- ip_addr ip_dest;
- Lap802_addr *lap_dest;
- {
- struct ipbuf *ipb;
- struct arp_header *arp_hdr;
- struct Lap802_header *lap_hdr;
- short oldPS;
-
- ipb = lap->arp_ipb;
- oldPS = Disable();
-
- if (ipb->iop.ioResult <= 0) {
- /* ipbuf available for sending ARPs */
-
- lap_hdr = (struct Lap802_header *)ipb->laphdr.ptr;
- lap_hdr->lap_dest = *lap_dest;
- lap_hdr->lap_ls.lap_type = LAP_ARP;
-
- arp_hdr = (struct arp_header *)ipb->ip.ptr;
- arp_hdr->arp_opcode = arp_code;
- arp_hdr->arp_sha = lap->our_lap_addr;
- arp_hdr->arp_spa = lap->our_ip_addr;
- arp_hdr->arp_tha = *lap_dest;
- arp_hdr->arp_tpa = ip_dest;
-
- /* call the IEEE 802.3 direct-write routine since we don't want to search the
- ARP table again! */
- Lap802_writeit(lap, ipb);
- }
- Enable(oldPS);
- }
-
-
- /* get_arp_entry is called to return a pointer to the ARP entry for the
- indicated IP address. Must be called with interrupts DISABLED to ensure
- consistent state of ARP table. */
-
- struct arp_entry *get_arp_entry(lap, addr)
- struct Lap802Info *lap;
- ip_addr addr;
- {
- struct arp_entry *ap;
-
- for (ap = &lap->arp_table[0]; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
- /* Is the pair <protocol type, protocol address> in the arp table? */
- if (ap->ip_address == addr) {
- /* If yes, return entry pointer */
- return(ap);
- }
- }
- return(nil);
- }
-
- /* new_arp_entry is called to return a pointer to a new ARP entry in the ARP table.
- Either an unused entry or the old entry in the table is returned. Interrupts
- must be disabled when calling this routine */
-
- struct arp_entry *new_arp_entry(lap, prot, sha, spa)
- struct Lap802Info *lap;
- b_16 prot;
- Lap802_addr sha;
- ip_addr spa;
- {
- struct arp_entry *ap, *oldest_ap;
- int oldest_age;
- short oldPS;
-
- ap = &lap->arp_table[0];
-
- oldPS = Disable();
- oldest_ap = ap;
- oldest_age = ap->age;
- for (; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
- if (ap->ip_address == 0) {
- /* found unused entry, return it */
- oldest_ap = ap;
- break;
- }
- else if (ap->age > oldest_age) {
- oldest_ap = ap;
- oldest_age = ap->age;
- }
- }
-
- oldest_ap->age = 0;
- oldest_ap->protocol = prot;
- oldest_ap->lap_address = sha;
- oldest_ap->ip_address = spa;
-
- Enable(oldPS);
- return(oldest_ap);
- }
-
- void del_arp_entry(lap, addr)
- struct Lap802Info *lap;
- ip_addr addr;
- {
- struct arp_entry *ap;
- short oldPS;
-
- oldPS = Disable();
- for (ap = &lap->arp_table[0]; ap < &lap->arp_table[ARP_TABLE_SIZE]; ap++) {
- /* Is the pair <protocol type, protocol address> in the arp table? */
- if (ap->ip_address == addr) {
- /* If yes, zero its entry */
- bzero((Ptr)ap, sizeof(struct arp_entry));
- break;
- }
- }
- Enable(oldPS);
- }
-
- /* BroadcastAddr is called to verify that the indicated address isn't a
- broadcast address */
-
- Boolean broadcastAddr(lap, addr)
- struct LAPInfo *lap;
- ip_addr addr;
- {
- ip_addr netmask;
-
- /* check for 255.255.255.255 broadcast addr */
- if (addr == 0xffffffff)
- return(true);
-
- /* check for net.subnet.255.255 broadcast addr */
- if ((addr | lap->our_net_mask) == 0xffffffff)
- return(true);
-
- /* check for net.255.255.255 broadcast addr */
- if ((lap->our_ip_addr & 0x80000000) == 0)
- netmask = 0xFF000000;
- else if ((lap->our_ip_addr & 0x40000000) == 0)
- netmask = 0xFFFF0000;
- else
- netmask = 0xFFFFFF00;
- if ((addr | netmask) == 0xffffffff)
- return(true);
-
- /* check for 0.0.0.0 broadcast addr */
- if (addr == 0x0)
- return(true);
-
- /* check for net.subnet.0.0 broadcast addr */
- if (addr == (lap->our_ip_addr & netmask))
- return(true);
- return(false);
- }
-